package xyz.xmh.pattern.creational.singletonpattern;

import java.util.concurrent.ArrayBlockingQueue;
import java.util.concurrent.ThreadPoolExecutor;
import java.util.concurrent.TimeUnit;

/**
 * SingletonPatternDemo
 *
 * @author xuMingHai
 * @since 2021/4/27 星期二 17:44
 */
public class SingletonPatternDemo {

    /**
     * 自定义一个简单的线程池
     */
    private static final ThreadPoolExecutor SIMPLE_THREAD_POOL = new ThreadPoolExecutor(0, 100, 10, TimeUnit.MICROSECONDS, new ArrayBlockingQueue<>(40), r -> {
        Thread thread = new Thread(r);
        thread.setName("simpleThread");
        return thread;
    });

    public static void main(String[] args) {
        // 饿汉单例模式，线程安全
        HungrySingleton.getInstance().showMessage();

        // 懒汉式，线程不安全的，懒加载
        LazySingleton instance1 = LazySingleton.getInstance();
        // 打印消息测试
        instance1.showMessage();
        // 再次获取实例，判断是否是同一个对象
        System.out.println("懒汉不加锁是否为同一对象：" + (instance1 == LazySingleton.getInstance()));

        // 懒汉式，加锁，线程安全，懒加载，性能不高
        LazyLockSingleton instance2 = LazyLockSingleton.getInstance();
        instance2.showMessage();
        System.out.println("懒汉加锁是否为同一对象：" + (instance2 == LazyLockSingleton.getInstance()));

        // 双检锁单例，加锁，线程安全，比较高效，懒加载
        DoubleCheckedLockSingleton instance3 = DoubleCheckedLockSingleton.getInstance();
        instance3.showMessage();
        System.out.println("双检锁是否为同一对象：" + (instance3 == DoubleCheckedLockSingleton.getInstance()));

        // 静态内部类单例，线程安全，懒加载，比较高效
        StaticClassSingleton instance4 = StaticClassSingleton.getInstance();
        instance4.showMessage();
        System.out.println("静态内部类单例是否为同一对象：" + (instance4 == StaticClassSingleton.getInstance()));

        // 枚举单例，线程安全，高效，懒加载，是单元素实例对象的最佳解决方案
        EnumSingleton.Resource instance5 = EnumSingleton.INSTANCE.getInstance();
        instance5.showMessage();

        // 多线程测试
        int frequency = 100;
        for (int i = 0; i < frequency; i++) {

            SIMPLE_THREAD_POOL.execute(() -> {
                if (instance4 != StaticClassSingleton.getInstance()) {
                    System.out.println("不同的两个对象");
                }
            });

        }


    }


}
